package com.fingard.dsp.bank.directbank.czb03;

import com.alibaba.dubbo.common.URL;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fingard.constant.Format;
import com.fingard.dsp.bank.directbank.DirectBase;
import com.fingard.dsp.bankset.BankFront;
import com.fingard.net.ConnState;
import com.fingard.net.ITcpClient;
import com.fingard.net.TcpReceiver;
import com.fingard.net.WebRequest;
import com.fingard.text.StringHelper;
import com.fingard.xml.XmlTextWriter;
import com.google.gson.Gson;
import com.koalii.svs.SvsSign;
import org.springframework.util.Base64Utils;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description TODO
 * @Author xtt
 * @Date $ $
 **/
public class CZB03Base extends DirectBase implements ITcpClient {

    protected static final String INSERTSEQ = "INSERT INTO REQSEQIDMAPPING(URID,BANKCODE,TRANSDATE,REQSEQID,BANKREQSEQID) values (?,?,?,?,?);";
    protected static final String SELECTSEQ = "SELECT BANKREQSEQID FROM REQSEQIDMAPPING WHERE REQSEQID=? AND BANKCODE=?;";


    /**
     * 浙商银行正确返回code值
     * */
    public static String bankRetRightCode = "000000";

    /**1-出票*/
    String drawBill = "1";
    /**2-承兑*/
    String acceptBill = "2";
    /**3-收票*/
    String receiveBill = "3";
    /**4-背书转让*/
    String endo = "4";
    /**5-质押*/
    String pledge =  "5";
    /**6-解质押*/
    String hypothecation = "6";
    /**7-出票保证*/
    String drawGurantee = "7";
    /**8-承兑保证*/
    String accGurantee = "8";
    /**9-背书保证*/
    String endoGurantee = "9";
    /**10-贴现*/
    String payCash =  "10";
    /**11-可回购式贴现*/
    String redem = "11";
    /**12-提示付款*/
    String payNotice = "12";
    /**13-可追索*/
    String search  = "13";
    /**14-同意清偿*/
    String agreePay = "14";

    /**1-申请*/
    String apply = "1";
    /**2-拒绝*/
    String receive = "2";
    /**3-驳回*/
    String reject = "3";
    /**4-撤销*/
    String cancel = "4";

    @Override
    public void getContentLength(TcpReceiver p_receiver) throws Exception {

    }

    protected String writeRequestJson(HashMap<String, Object> body, CZB03Header czb01Header) throws Exception {
        //json数据格式
        JSONObject sigJson = new JSONObject();
        JSONObject reqJson = new JSONObject();
        HashMap<String, String> header = new HashMap<String, String>();
        HashMap<String, Object> signbody = new HashMap<String, Object>();

        header.put("appid", getBankConfig().getValueAsString("appid"));
        header.put("openid", getBankConfig().getValueAsString("openid"));
        header.put("sendtime", Format.DateTime23Format.format(new Date()));
        header.put("termianatype", czb01Header.transCode);
        header.put("traceno", czb01Header.reqSeqNo);
        sigJson.put("header", header);
        signbody.put("signbody", sigJson);
        reqJson.put("request", signbody);
        String jsonStr = reqJson.toJSONString();

        String appkey = getBankConfig().getValueAsString("appkey");
        String sig = getSignature(sigJson.toString().getBytes("UTF-8"), appkey.getBytes());
        String cfcaSig = getCFCASignature(sigJson.toString().getBytes("UTF-8"));
   //     reqJson.put("keysign", sig);
        jsonStr = jsonStr.substring(0,jsonStr.length()-1)+","+"\"keysign\":"+"\""+sig+"\"";
        //调整位置
        jsonStr = jsonStr +","+"\"cfcasign\":"+"\""+cfcaSig+"\""+"}";
        //计算token是否过期
        if (isExpireToken()) {
            WriteBankLogLn("发送给银行获取token的报文：" + jsonStr);
            header.put("token", getToken(jsonStr.getBytes()));
        }else{
            header.put("token", bankFront.token);
        }
        sigJson.clear();
        sigJson.put("body", body);
        String bodyStr = sigJson.toJSONString();
        sigJson.put("header",header);
        String headerStr = sigJson.toJSONString();
        bodyStr = bodyStr.substring(0,bodyStr.length()-1)+","+headerStr.substring(1,headerStr.length());
      //  sigJson.put("header", header);
        signbody.put("signbody", sigJson);
        reqJson.clear();
        reqJson.put("request", signbody);
        String sigBody = getSignature(sigJson.toJSONString().getBytes("UTF-8"), appkey.getBytes());
        String cfcaSigBody = getCFCASignature(sigJson.toJSONString().getBytes("UTF-8"));
        String str = reqJson.toJSONString();
        str = str.substring(0,str.length()-1)+","+"\"keysign\":"+"\""+sigBody+"\"";

        //调整位置
        str = str + ","+"\"cfcasign\":"+"\""+cfcaSigBody+"\""+"}";
        return str;
    }

    public String getCFCASignature(byte[] data) {
        try {
            SvsSign svsSig = new SvsSign();
            svsSig.initSignCertAndKey(getBankConfig().getValueAsString("pfxPath"), getBankConfig().getValueAsString("pfxpassword"));//conf为配置对象用
            return svsSig.pkcs7SignData(data);
        } catch (Exception e) {
            return null;
        }
    }

    protected String[] sendToBank(String p_reqStr) throws Exception {
        //一：参数、对象定义
        String[] retStrArr = new String[]{"", ""};
        String url = bankFront.serverURL;
        WriteBankLogLn("提交银行的地址为：" + url);
        WriteBankLogLn("提交银行的报文为：" + p_reqStr);
        WebRequest tmpWebRequest = new WebRequest(url);
        tmpWebRequest.setConnectTimeout(60000);
        tmpWebRequest.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        tmpWebRequest.setRequestProperty("connection", "Close");
        retStrArr = tmpWebRequest.upload(p_reqStr.getBytes(), getCharset());
        WriteBankLogStep3(retStrArr[1]);
        return retStrArr;
    }

    public static String getSignature(byte[] data, byte[] key) {
        try {
            SecretKey signingKey = new SecretKeySpec(key, "HmacSHA1");
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(signingKey);
            byte[] rawHmac = mac.doFinal(data);
            String sig = Base64Utils.encodeToString(rawHmac);
            return sig;
        } catch (Exception e) {
            return null;
        }
    }

    public String getToken(byte[] data) {
        try {
            String[] retStr = new String[]{"", ""};
            String url = "http://"+bankFront.serverIP + ":" + bankFront.serverPort + "/api/token";
            WriteBankLogLn("提交银行进行签名的地址为：" + url);
            WebRequest tmpWebRequest = new WebRequest(url);
            tmpWebRequest.setConnectTimeout(60000);
            tmpWebRequest.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            tmpWebRequest.setRequestProperty("connection", "Close");
            retStr = tmpWebRequest.upload(data, getCharset());
            if (retStr[0].length() == 0 && retStr[1].contains("get token error")) {
                bankFront.token = "";
            }
            WriteBankLogStep3(retStr[1]);

            JSONObject json = JSONObject.parseObject(retStr[1]);
            String repCode = json.getString("resultcode");
            if(repCode.equals("000000")) {
                String body = json.getString("body");
                Map<String, String> bodyInfo = new HashMap<String, String>();
                Gson gson = new Gson();
                bodyInfo = gson.fromJson(body, bodyInfo.getClass());
                bankFront.token = bodyInfo.get("token");
                bankFront.lastLoginTime = new Date();
            }else{
                bankFront.token = "";
            }
            return bankFront.token;
        } catch (Exception e) {
            return null;
        }
    }

    //超时时间20分钟，容错5秒(银行规定20分钟同时存在3个token)
    public boolean isExpireToken(){
        if(bankFront.lastLoginTime == null){
            return true;
        }
        long lastTime = bankFront.lastLoginTime.getTime();
        long nowTime = System.currentTimeMillis();
        long time = 1195*60*1000;
        if((nowTime - lastTime)>time){
            bankFront.token = "";
            return true;
        } else if (StringHelper.isNullOrEmpty(bankFront.token)){
            return true;
        }
        return true;
    }

    public String getLastYearDate(){
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.MONTH, -2);
        Date y = c.getTime();
        String year = format.format(y);
        return year;
    }

    public String getafterMouthDate(){
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.MONTH, 1);
        Date y = c.getTime();
        String year = format.format(y);
        return year;
    }

    public String getCharset() {
        return "UTF-8";
    }
}
